package org.acghub.common.reload;


import org.acghub.common.Pair;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class CfgReloader implements Reloader<Reloader.Args, CfgReloader.CfgResult> {

    static CfgResult reload(String cfgDir, List<String> cfgClassNames) {
        CfgResult result = new CfgResult();

        if (cfgDir == null || cfgDir.isEmpty()) {
            return result.failed(String.format("cfgDir invalid, cfgDir=%s", cfgDir));
        }
        if (cfgClassNames == null || cfgClassNames.isEmpty()) {
            return result.failed(String.format("cfgClassNames invalid, cfgClassNames=%s", cfgClassNames));
        }

        Set<String> classNames = new LinkedHashSet<>(cfgClassNames);
        List<ReloadCfgWrapper> cfgWrappers = classNames.stream().map(ReloadCfgWrapper::new).toList();
        try {
            for (ReloadCfgWrapper cfgWrapper : cfgWrappers) {
                if (!cfgWrapper.parse()) {
                    result.failedPairs.add(new Pair<>(cfgWrapper.getCfgClassName(), cfgWrapper.getCause()));
                }
            }
            if (!result.failedPairs.isEmpty()) {
                return result.failed("cfgClassNames parse failed, please to see failedPairs field");
            }

            for (ReloadCfgWrapper cfgWrapper : cfgWrappers) {
                if (!cfgWrapper.reload(cfgDir)) {
                    result.failedPairs.add(new Pair<>(cfgWrapper.getCfgClassName(), cfgWrapper.getCause()));
                }
            }
            if (!result.failedPairs.isEmpty()) {
                return result.failed("cfgClassNames reload failed, please to see failedPairs field");
            }


            for (ReloadCfgWrapper cfgWrapper : cfgWrappers) {
                if (!cfgWrapper.update()) {
                    cfgWrapper.recover();
                    result.failedPairs.add(new Pair<>(cfgWrapper.getCfgClassName(), cfgWrapper.getCause()));
                    return result.failed("cfgClassNames reload failed, please to see failedPairs field");
                }
            }
        } catch (Throwable e) {
            result.failed(e);
        } finally {
            for (ReloadCfgWrapper cfgWrapper : cfgWrappers) {
                cfgWrapper.close();
            }
        }
        return result;
    }

    @Override
    public CfgResult reload(Args args) {
        return reload(args.dir(), args.classNames());
    }

    public static class CfgResult extends Reloader.Result {
        public final List<Pair<String, Throwable>> failedPairs = new ArrayList<>();

        public CfgResult failed(Object reason) {
            super.fail(reason);
            return this;
        }
    }
}
